home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / manual-p / man_db-2.000 / man_db-2 / man_db-2.3.10 / lib / realpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-04  |  3.9 KB  |  169 lines

  1. /*
  2.  * realpath.c -- canonicalize pathname by removing symlinks
  3.  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU Library Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU Library Public License for more details.
  14.  */
  15.  
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19.  
  20. #include <sys/types.h>
  21. #if defined(HAVE_UNISTD_H) || defined(STDC_HEADERS)
  22. #include <unistd.h>
  23. #endif
  24. #include <stdio.h>
  25. #ifdef HAVE_STRING_H
  26. #include <string.h>
  27. #else
  28. #include <strings.h>
  29. #endif
  30. #ifdef _POSIX_VERSION
  31. #include <limits.h>            /* for PATH_MAX */
  32. #else
  33. #include <sys/param.h>            /* for MAXPATHLEN */
  34. #endif
  35. #include <errno.h>
  36.  
  37. #ifndef STDC_HEADERS
  38. extern int errno;
  39. #endif
  40.  
  41. #include <sys/stat.h>            /* for S_IFLNK */
  42.  
  43. #ifndef PATH_MAX
  44. #ifdef _POSIX_VERSION
  45. #define PATH_MAX _POSIX_PATH_MAX
  46. #else
  47. #ifdef MAXPATHLEN
  48. #define PATH_MAX MAXPATHLEN
  49. #else
  50. #define PATH_MAX 1024
  51. #endif
  52. #endif
  53. #endif
  54.  
  55. #define MAX_READLINKS 32
  56.  
  57. #ifdef __STDC__
  58. char *realpath(const char *path, char resolved_path [])
  59. #else
  60. char *realpath(path, resolved_path)
  61. const char *path;
  62. char resolved_path [];
  63. #endif
  64. {
  65.     char copy_path[PATH_MAX];
  66.     char link_path[PATH_MAX];
  67.     char *new_path = resolved_path;
  68.     char *max_path;
  69.     int readlinks = 0;
  70.     int n;
  71.  
  72.     /* Make a copy of the source path since we may need to modify it. */
  73.     strcpy(copy_path, path);
  74.     path = copy_path;
  75.     max_path = copy_path + PATH_MAX - 2;
  76.     /* If it's a relative pathname use getwd for starters. */
  77.     if (*path != '/') {
  78. #ifdef HAVE_GETCWD
  79.         getcwd(new_path, PATH_MAX - 1);
  80. #else
  81.         getwd(new_path);
  82. #endif
  83.         new_path += strlen(new_path);
  84.         if (new_path[-1] != '/')
  85.             *new_path++ = '/';
  86.     }
  87.     else {
  88.         *new_path++ = '/';
  89.         path++;
  90.     }
  91.     /* Expand each slash-separated pathname component. */
  92.     while (*path != '\0') {
  93.         /* Ignore stray "/". */
  94.         if (*path == '/') {
  95.             path++;
  96.             continue;
  97.         }
  98.         if (*path == '.') {
  99.             /* Ignore ".". */
  100.             if (path[1] == '\0' || path[1] == '/') {
  101.                 path++;
  102.                 continue;
  103.             }
  104.             if (path[1] == '.') {
  105.                 if (path[2] == '\0' || path[2] == '/') {
  106.                     path += 2;
  107.                     /* Ignore ".." at root. */
  108.                     if (new_path == resolved_path + 1)
  109.                         continue;
  110.                     /* Handle ".." by backing up. */
  111.                     while ((--new_path)[-1] != '/')
  112.                         ;
  113.                     continue;
  114.                 }
  115.             }
  116.         }
  117.         /* Safely copy the next pathname component. */
  118.         while (*path != '\0' && *path != '/') {
  119.             if (path > max_path) {
  120.                 errno = ENAMETOOLONG;
  121.                 return NULL;
  122.             }
  123.             *new_path++ = *path++;
  124.         }
  125. #ifdef S_IFLNK
  126.         /* Protect against infinite loops. */
  127.         if (readlinks++ > MAX_READLINKS) {
  128.             errno = ELOOP;
  129.             return NULL;
  130.         }
  131.         /* See if latest pathname component is a symlink. */
  132.         *new_path = '\0';
  133.         n = readlink(resolved_path, link_path, PATH_MAX - 1);
  134.         if (n < 0) {
  135.             /* EINVAL means the file exists but isn't a symlink. */
  136.             if (errno != EINVAL)
  137.                 return NULL;
  138.         }
  139.         else {
  140.             /* Note: readlink doesn't add the null byte. */
  141.             link_path[n] = '\0';
  142.             if (*link_path == '/')
  143.                 /* Start over for an absolute symlink. */
  144.                 new_path = resolved_path;
  145.             else
  146.                 /* Otherwise back up over this component. */
  147.                 while (*(--new_path) != '/')
  148.                     ;
  149.             /* Safe sex check. */
  150.             if (strlen(path) + n >= PATH_MAX) {
  151.                 errno = ENAMETOOLONG;
  152.                 return NULL;
  153.             }
  154.             /* Insert symlink contents into path. */
  155.             strcat(link_path, path);
  156.             strcpy(copy_path, link_path);
  157.             path = copy_path;
  158.         }
  159. #endif /* S_IFLNK */
  160.         *new_path++ = '/';
  161.     }
  162.     /* Delete trailing slash but don't whomp a lone slash. */
  163.     if (new_path != resolved_path + 1 && new_path[-1] == '/')
  164.         new_path--;
  165.     /* Make sure it's null terminated. */
  166.     *new_path = '\0';
  167.     return resolved_path;
  168. }
  169.